package com.crazymaker.springcloud.back.end.controller;

import com.crazymaker.springcloud.back.end.service.impl.SysUserAuthService;
import com.crazymaker.springcloud.base.security.token.MobileAuthenticationToken;
import com.crazymaker.springcloud.base.security.token.OpenIdAuthenticationToken;
import com.crazymaker.springcloud.common.util.ResponseUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.exceptions.UnapprovedClientAuthenticationException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * OAuth2相关操作
 *
 * @author zlt
 */
@Api(tags = "OAuth2相关操作" )
@Slf4j
@RestController
public class OAuth2Controller
{
    @Resource
    private ObjectMapper objectMapper;

    @Resource
    private SysUserAuthService userAuthService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Resource
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Resource
    private AuthenticationManager authenticationManager;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @ApiOperation(value = "用户名密码获取token" )
    @PostMapping("/oauth/user/token" )
    public void getUserTokenInfo(
            String username,
            String password,
            String deviceId,
            String validCode,
            HttpServletRequest request, HttpServletResponse response) throws IOException
    {
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        writerToken(request, response, token, "用户名或密码错误" );
    }

    @ApiOperation(value = "openId获取token" )
    @PostMapping("/oauth/openId/token" )
    public void getTokenByOpenId(
            @ApiParam(required = true, name = "openId", value = "openId" ) String openId,
            HttpServletRequest request, HttpServletResponse response) throws IOException
    {
        OpenIdAuthenticationToken token = new OpenIdAuthenticationToken(openId);
        writerToken(request, response, token, "openId错误" );
    }

    @ApiOperation(value = "mobile获取token" )
    @PostMapping("/oauth/mobile/token" )
    public void getTokenByMobile(
            @ApiParam(required = true, name = "mobile", value = "mobile" ) String mobile,
            @ApiParam(required = true, name = "password", value = "密码" ) String password,
            HttpServletRequest request, HttpServletResponse response) throws IOException
    {
        MobileAuthenticationToken token = new MobileAuthenticationToken(mobile, password);
        writerToken(request, response, token, "手机号或密码错误" );
    }

    private void writerToken(HttpServletRequest request,
                             HttpServletResponse response,
                             AbstractAuthenticationToken token,
                             String badCredenbtialsMsg) throws IOException
    {
        try
        {


            Authentication authentication = authenticationManager.authenticate(token);
            SecurityContextHolder.getContext().setAuthentication(authentication);
            OAuth2AccessToken oAuth2AccessToken = userAuthService.login(authentication);

//            authentication.setAuthenticated(true);

            ResponseUtil.responseSucceed(objectMapper, response, oAuth2AccessToken);
        } catch (BadCredentialsException | InternalAuthenticationServiceException e)
        {
            exceptionHandler(response, badCredenbtialsMsg);
        } catch (Exception e)
        {
            exceptionHandler(response, e);
        }
    }

    private void exceptionHandler(HttpServletResponse response, Exception e) throws IOException
    {
        log.error("exceptionHandler-error:", e);
        exceptionHandler(response, e.getMessage());
    }

    private void exceptionHandler(HttpServletResponse response, String msg) throws IOException
    {
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        ResponseUtil.responseFailed(objectMapper, response, msg);
    }

    private ClientDetails getClient(String clientId, String clientSecret)
    {
        ClientDetails clientDetails = clientDetailsService.loadClientByClientId(clientId);

        if (clientDetails == null)
        {
            throw new UnapprovedClientAuthenticationException("clientId对应的信息不存在" );
        } else if (!passwordEncoder.matches(clientSecret, clientDetails.getClientSecret()))
        {
            throw new UnapprovedClientAuthenticationException("clientSecret不匹配" );
        }
        return clientDetails;
    }
}
